package com.nnnu.wsnackshop.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nnnu.wsnackshop.exception.ObjectException;
import com.nnnu.wsnackshop.pojo.dto.AddCategoryDTO;
import com.nnnu.wsnackshop.pojo.dto.CategoryPageDTO;
import com.nnnu.wsnackshop.pojo.dto.ImportCategoryDTO;
import com.nnnu.wsnackshop.pojo.dto.UpdateCategoryDTO;
import com.nnnu.wsnackshop.pojo.entity.Categories;
import com.nnnu.wsnackshop.mapper.CategoriesMapper;
import com.nnnu.wsnackshop.pojo.vo.CategoryVO;
import com.nnnu.wsnackshop.pojo.vo.ExportCategoryVO;
import com.nnnu.wsnackshop.result.PageResult;
import com.nnnu.wsnackshop.service.ICategoriesService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 商品分类 服务实现类
 * </p>
 *
 * @author zk
 * @since 2025-05-14
 */
@RequiredArgsConstructor
@Service
public class CategoriesServiceImpl extends ServiceImpl<CategoriesMapper, Categories> implements ICategoriesService {
    private static final DateTimeFormatter FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Override
    public PageResult<CategoryVO> pageCategories(CategoryPageDTO dto) {
        Page<Categories> page = new Page<>(dto.getPageNum(), dto.getPageSize());
        LambdaQueryWrapper<Categories> qw = Wrappers.<Categories>lambdaQuery()
                .like(StrUtil.isNotBlank(dto.getKeyword()), Categories::getName, dto.getKeyword())
                .eq(dto.getStatus() != null, Categories::getStatus, dto.getStatus())
                .orderByAsc(Categories::getSort);
        Page<Categories> res = baseMapper.selectPage(page, qw);

        Map<Integer, String> idNameMap = baseMapper.selectList(null)
                .stream().collect(Collectors.toMap(Categories::getId, Categories::getName));

        List<CategoryVO> vos = res.getRecords().stream().map(cat -> {
            CategoryVO vo = BeanUtil.toBean(cat, CategoryVO.class);
            vo.setParentName(idNameMap.get(cat.getParentId()));
            return vo;
        }).collect(Collectors.toList());

        return PageResult.<CategoryVO>builder()
                .total(res.getTotal())
                .items(vos)
                .build();
    }

    @Override
    public List<CategoryVO> listTree() {
        List<Categories> all = baseMapper
                .selectList(Wrappers.<Categories>lambdaQuery().orderByAsc(Categories::getSort));
        Map<Integer, List<Categories>> childrenMap = all.stream()
                .filter(c -> c.getParentId() != null)
                .collect(Collectors.groupingBy(Categories::getParentId));

        Map<Integer, String> idNameMap = all.stream()
                .collect(Collectors.toMap(Categories::getId, Categories::getName));

        return all.stream()
                .filter(c -> c.getParentId() == null)
                .map(c -> buildTree(c, childrenMap, idNameMap))
                .collect(Collectors.toList());
    }

    private CategoryVO buildTree(Categories c, Map<Integer, List<Categories>> childrenMap,
            Map<Integer, String> idNameMap) {
        CategoryVO vo = BeanUtil.toBean(c, CategoryVO.class);
        vo.setParentName(idNameMap.get(c.getParentId()));
        List<Categories> children = childrenMap.get(c.getId());
        if (children != null) {
            vo.setChildren(children.stream()
                    .map(child -> buildTree(child, childrenMap, idNameMap))
                    .collect(Collectors.toList()));
        }
        return vo;
    }

    @Override
    public void addCategory(AddCategoryDTO dto) {
        Categories c = BeanUtil.toBean(dto, Categories.class);
        save(c);
    }

    @Override
    public void updateCategory(UpdateCategoryDTO dto) {
        Categories cat = getById(dto.getId());
        if (cat == null)
            throw new ObjectException("分类不存在");
        LambdaUpdateWrapper<Categories> uw = Wrappers.<Categories>lambdaUpdate()
                .eq(Categories::getId, dto.getId());
        uw.set(StrUtil.isNotBlank(dto.getName()), Categories::getName, dto.getName());
        uw.set(dto.getParentId() != null, Categories::getParentId, dto.getParentId());
        uw.set(StrUtil.isNotBlank(dto.getDescription()), Categories::getDescription, dto.getDescription());
        uw.set(dto.getSort() != null, Categories::getSort, dto.getSort());
        uw.set(dto.getStatus() != null, Categories::getStatus, dto.getStatus());
        uw.set(dto.getIconUrl() != null, Categories::getIconUrl, dto.getIconUrl());
        update(uw);
    }

    @Override
    public void deleteCategory(Integer id) {
        long children = count(Wrappers.<Categories>lambdaQuery().eq(Categories::getParentId, id));
        if (children > 0)
            throw new ObjectException("请先删除子分类");
        removeById(id);
    }

    @Override
    public void updateStatus(Integer id, Integer status) {
        Categories cat = getById(id);
        if (cat == null)
            throw new ObjectException("分类不存在");
        cat.setStatus(status);
        updateById(cat);
    }

    @Override
    public void updateSort(Integer id, Integer sort) {
        Categories cat = getById(id);
        if (cat == null)
            throw new ObjectException("分类不存在");
        cat.setSort(sort);
        updateById(cat);
    }

    @Override
    public CategoryVO getCategoryDetail(Integer id) {
        Categories cat = getById(id);
        if (cat == null)
            throw new ObjectException("分类不存在");
        CategoryVO vo = BeanUtil.toBean(cat, CategoryVO.class);
        if (cat.getParentId() != null) {
            Categories parent = getById(cat.getParentId());
            if (parent != null) {
                vo.setParentName(parent.getName());
            }
        }
        return vo;
    }

    @Override
    public List<CategoryVO> listTopCategories() {
        List<Categories> categories = lambdaQuery()
                .isNull(Categories::getParentId)
                .eq(Categories::getStatus, 1) // 可选：只缓存启用状态
                .orderByAsc(Categories::getSort)
                .list();

        return categories.stream()
                .map(cat -> {
                    CategoryVO vo = BeanUtil.toBean(cat, CategoryVO.class);
                    vo.setParentName("顶级分类");
                    return vo;
                })
                .collect(Collectors.toList());
    }

    @Override
    public List<CategoryVO> getTopCategories() {
        // 复用现有的listTopCategories方法
        return listTopCategories();
    }

    @Override
    public List<CategoryVO> listChildCategories(Integer parentId) {
        List<Categories> categories = lambdaQuery()
                .eq(Categories::getParentId, parentId)
                .eq(Categories::getStatus, 1)
                .orderByAsc(Categories::getSort)
                .list();

        // 获取父分类名称
        String parentName = "";
        if (parentId != null && parentId != 0) {
            Categories parent = getById(parentId);
            if (parent != null) {
                parentName = parent.getName();
            }
        }

        final String finalParentName = parentName;
        return categories.stream()
                .map(cat -> {
                    CategoryVO vo = BeanUtil.toBean(cat, CategoryVO.class);
                    vo.setParentName(finalParentName);
                    return vo;
                })
                .collect(Collectors.toList());
    }

    @Override
    public List<CategoryVO> getCategoryTree() {
        return listTree();
    }

    @Override
    public List<CategoryVO> listAllCategories() {
        List<Categories> categories = lambdaQuery()
                .eq(Categories::getStatus, 1)
                .orderByAsc(Categories::getSort)
                .list();

        Map<Integer, String> idNameMap = categories.stream()
                .collect(Collectors.toMap(Categories::getId, Categories::getName));

        return categories.stream()
                .map(cat -> {
                    CategoryVO vo = BeanUtil.toBean(cat, CategoryVO.class);
                    vo.setParentName(idNameMap.get(cat.getParentId()));
                    return vo;
                })
                .collect(Collectors.toList());
    }

    @Override
    public void exportCategories(HttpServletResponse response) throws IOException {
        List<Categories> categories = baseMapper.selectList(null);
        List<ExportCategoryVO> list = categories.stream().map(c -> {
            ExportCategoryVO vo = BeanUtil.toBean(c, ExportCategoryVO.class);
            if (c.getParentId() != null && c.getParentId() != 0) {
                Categories parent = baseMapper.selectById(c.getParentId());
                if (parent != null)
                    vo.setParentName(parent.getName());
            } else {
                vo.setParentName("-");
            }
            vo.setCreatedAt(c.getCreateAt().format(FMT));
            vo.setUpdatedAt(c.getUpdateAt().format(FMT));
            return vo;
        }).collect(Collectors.toList());

        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setHeader("Content-Disposition", "attachment;filename=categories.xlsx");

        EasyExcel.write(response.getOutputStream(), ExportCategoryVO.class)
                .sheet("分类信息")
                .doWrite(list);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importCategories(MultipartFile file) throws IOException {
        List<ImportCategoryDTO> list = EasyExcel.read(file.getInputStream())
                .head(ImportCategoryDTO.class)
                .sheet()
                .doReadSync();

        for (ImportCategoryDTO dto : list) {
            Categories category = BeanUtil.toBean(dto, Categories.class);
            baseMapper.insert(category);
        }
    }

    @Override
    public void downloadTemplate(HttpServletResponse response) {
        try (Workbook workbook = new XSSFWorkbook()) {
            Sheet sheet = workbook.createSheet("分类模板");
            Row header = sheet.createRow(0);

            String[] titles = { "分类名称", "父分类ID", "描述", "排序", "状态（0-禁用，1-启用）" };
            for (int i = 0; i < titles.length; i++) {
                Cell cell = header.createCell(i);
                cell.setCellValue(titles[i]);
            }

            // 设置响应头
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Content-Disposition", "attachment; filename=category_template.xlsx");

            workbook.write(response.getOutputStream());
        } catch (IOException e) {
            throw new RuntimeException("模板下载失败", e);
        }
    }
}
